package com.town.garden.service.impl;

import com.town.garden.chain.AbstractServerStartHandler;
import com.town.garden.component.HeartbeatComponent;
import com.town.garden.constant.GlobalConstant;
import com.town.garden.enums.NVRApiEnum;
import com.town.garden.propertites.NvrProperties;
import com.town.garden.service.NvrLoginService;
import com.town.garden.storage.NvrSessionStorage;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.Objects;

/**
 * @Description
 * @E-mail cwm3412638@163.com
 * @Author cwm
 * @Date 2022/5/13
 */
@Service(NvrLoginServiceImpl.BEAN_NAME)
@Slf4j
public class NvrLoginServiceImpl extends AbstractServerStartHandler implements NvrLoginService {
    public static final String BEAN_NAME = "nvrLoginServiceImpl";
    @Autowired
    private NvrProperties nvrProperties;
    @Autowired
    private RestTemplate restTemplate;
    /**
     * 下一个责任链对象
     * {@linkplain HeartbeatComponent}
     */
    @Autowired
    @Qualifier(HeartbeatComponent.BEAN_NAME)
    private AbstractServerStartHandler abstractServerStartHandler;

    @Override
    public ResponseEntity<String> login() throws URISyntaxException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        //nvr 认证API
        final String url = GlobalConstant.HTTPS_PREFIX + nvrProperties.getNvrServerIp() + NVRApiEnum.LOGIN.getUrl();
        final URI serverUri = new URI(url);
        //跳过ssl验证
        TrustStrategy acceptingTrustStrategy = (x509Certificates, authType) -> true;
        SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
        SSLConnectionSocketFactory connectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
        //摘要认证时使用
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(new AuthScope(serverUri.getHost(), serverUri.getPort()),
                new UsernamePasswordCredentials(nvrProperties.getUserAccount(), nvrProperties.getUserPassWord()));
        final CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(connectionSocketFactory).setDefaultCredentialsProvider(credentialsProvider).build();
        final HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setHttpClient(httpclient);
        final RestTemplate restTemplate = new RestTemplate(factory);
        //向NVR  server发送登录认证请求
        try {
            return restTemplate.exchange(url, HttpMethod.POST, null, String.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public ResponseEntity<String> logout() {
        //拼接请求url
        final String url = GlobalConstant.HTTPS_PREFIX + nvrProperties.getNvrServerIp() + NVRApiEnum.LOGOUT.getUrl();
        final HttpEntity<?> entity = new HttpEntity<>(null, NvrSessionStorage.headers);
        try {
            return restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void handlerOperation() {
        try {
            ResponseEntity<String> login = login();
            if (Objects.nonNull(login) && HttpStatus.OK.equals(login.getStatusCode())) {
                log.info("login nvr server success");
                final String setCookie = Objects.requireNonNull(login.getHeaders().get(GlobalConstant.SET_COOKIE)).get(0);
                final String xCsrfToken = Objects.requireNonNull(login.getHeaders().get(GlobalConstant.X_CSRF_TOKEN)).get(0);
                //存储认证信息
                NvrSessionStorage.strCookie = setCookie;
                NvrSessionStorage.strXCsrfToken = xCsrfToken;
                //封装统一人证信息请求头
                final HttpHeaders headers = new HttpHeaders();
                headers.set(HttpHeaders.COOKIE, NvrSessionStorage.strCookie);
                headers.set(GlobalConstant.X_CSRF_TOKEN, NvrSessionStorage.strXCsrfToken);
                NvrSessionStorage.headers = headers;
                //调用下一个处理者
                abstractServerStartHandler.handlerOperation();
            } else {
                log.error("nvr login failed");
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }

    }
}
